package com.example.util;

import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.chinese.SolarTerms;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class TaoistsXLRUtil {
    /**
     * 地支
     */
    public static Map<Integer, String> DI_ZHI = new HashMap<>() {{
        put(1, "子");
        put(2, "丑");
        put(3, "寅");
        put(4, "卯");
        put(5, "辰");
        put(6, "巳");
        put(7, "午");
        put(8, "未");
        put(9, "申");
        put(10, "酉");
        put(11, "戌");
        put(12, "亥");
    }};

    /**
     * 五行生克 0:我生 1：我克 2：生我 3：克我
     */
    public static Map<String, String[]> WU_XING_SHENG_KE = new HashMap<>() {{
        put("金", new String[]{"水", "木", "土", "火"});
        put("木", new String[]{"火", "土", "水", "金"});
        put("水", new String[]{"木", "火", "金", "土"});
        put("火", new String[]{"土", "金", "木", "水"});
        put("土", new String[]{"金", "水", "火", "木"});
    }};

    /**
     * 地支五行
     */
    public static Map<String, String> DI_ZHI_WU_XING = new HashMap<>() {{
        put("子", "水");
        put("丑", "土");
        put("寅", "木");
        put("卯", "木");
        put("辰", "土");
        put("巳", "火");
        put("午", "火");
        put("未", "土");
        put("申", "金");
        put("酉", "金");
        put("戌", "土");
        put("亥", "水");
    }};

    /**
     * 地支六神
     */
    public static Map<String, String> DI_ZHI_LIU_SHENG = new HashMap<>() {{
        put("子", "玄武");
        put("丑", "勾陈");
        put("寅", "青龙");
        put("卯", "青龙");
        put("辰", "勾陈");
        put("巳", "朱雀");
        put("午", "朱雀");
        put("未", "腾蛇");
        put("申", "白虎");
        put("酉", "白虎");
        put("戌", "腾蛇");
        put("亥", "玄武");
    }};

    /**
     * 五星
     */
    public static String[] WU_XING = {"辅木", "英火", "芮土", "柱金", "蓬水", "任空"};
    /**
     * 活六神
     */
    public static String[] HUO_LIU_SHENG = {"青龙", "朱雀", "勾陈", "白虎", "玄武", "腾蛇"};
    /**
     * 活六神1
     */
    public static String[] HUO_LIU_SHENG1 = {"青龙", "腾蛇", "朱雀", "白虎", "玄武", "勾陈"};
    /**
     * 活六神1
     */
    public static String[] HUO_LIU_SHENG1_REVERSE = {"勾陈", "玄武", "白虎", "朱雀", "腾蛇", "青龙"};

    /**
     * 六宫
     */
    public static Map<Integer, String> LIU_GONG = new HashMap<>() {{
        put(1, "大安");
        put(2, "留连");
        put(3, "速喜");
        put(4, "赤口");
        put(5, "小吉");
        put(6, "空亡");
    }};

    public static Map<String, String> SAN_CAI = new HashMap<>() {{
        put("天生人 人生地", "时授");
        put("天生人 人克地", "仗权");
        put("天生人 人比地", "承恩");
        put("天克人 人生地", "愚执");
        put("天克人 人克地", "贼害");
        put("天克人 人比地", "时错");
        put("人比天 人生地", "泽民");
        put("人比天 人克地", "未刑");
        put("人生天 地生人", "谏言");
        put("人生天 地克人", "辙鱼");
        put("人生天 人比地", "既济");
        put("人克天 地生人", "上德");
        put("人克天 地克人", "反罡");
        put("人比天 地生人", "时捻");
        put("人克天 人比地", "反刃");
        put("人比天 地克人", "失位");
        put("天生人 地克人", "抚躬");
        put("天克人 地克人", "同嫉");
        put("天克人 地生人", "成丹");
        put("天生人 地生人", "育贤");
        put("人克天 人克地", "立身");
        put("人生天 人生地", "格物");
        put("人生天 人克地", "省仕");
        put("人克天 人生地", "秉烛");
        put("人比天 人比地", "守元");
    }};

    /**
     * 阳地支
     */
    public static int[] YANG_DI_ZHI = {1, 3, 5, 7, 9, 11};
    /**
     * 阴地支
     */
    public static int[] YIN_DI_ZHI = {2, 4, 6, 8, 10, 12};

    /**
     * 获取农历相关时间的方法
     */
    public static Map<String, String> getChineseDate() {
        // 农历时间
        LocalDateTime now = LocalDateTimeUtil.now();
        return getChineseTime(now);
    }

    /**
     * 获取农历相关时间的方法
     */
    public static Map<String, String> getChineseDate(String dateStr) {
        DateTime dateTime = DateUtil.parseDateTime(dateStr);
        LocalDateTime localDateTime = DateUtil.toLocalDateTime(dateTime);

        return getChineseTime(localDateTime);
    }

    private static Map<String, String> getChineseTime(LocalDateTime localDateTime) {
        Map<String, String> result = new HashMap<>();

        ChineseDate chineseDate = new ChineseDate(LocalDate.from(localDateTime));

        result.put("date", chineseDate.toStringNormal());
        result.put("chineseDate", chineseDate.toString());
        result.put("chineseDateAll", chineseDate.getCyclicalYMD());
        result.put("term", SolarTerms.getTerm(chineseDate));

        String chineseTime = getTime(localDateTime);
        result.put("chineseTime", chineseTime);

        return result;
    }

    private static String getTime(LocalDateTime localDateTime) {
        String chineseTime = "";
        int hour = localDateTime.getHour();
        if (hour >= 1 && hour < 3) {
            chineseTime = "丑";
        } else if (hour >= 3 && hour < 5) {
            chineseTime = "寅";
        } else if (hour >= 5 && hour < 7) {
            chineseTime = "卯";
        } else if (hour >= 7 && hour < 9) {
            chineseTime = "辰";
        } else if (hour >= 9 && hour < 11) {
            chineseTime = "巳";
        } else if (hour >= 11 && hour < 13) {
            chineseTime = "午";
        } else if (hour >= 13 && hour < 15) {
            chineseTime = "未";
        } else if (hour >= 15 && hour < 17) {
            chineseTime = "申";
        } else if (hour >= 17 && hour < 19) {
            chineseTime = "酉";
        } else if (hour >= 19 && hour < 21) {
            chineseTime = "戌";
        } else if (hour >= 21 && hour < 23) {
            chineseTime = "亥";
        } else {
            chineseTime = "子";
        }
        return chineseTime;
    }

    /**
     * 定六亲
     */
    public static Map<String, String> getLiuQin(String diZhi) {
        Map<String, String> result = new HashMap<>();
        if ("子".equals(diZhi)) {
            result.put("子", "自身");
            result.put("辰", "兄弟");
            result.put("寅", "子孙");
            result.put("戌", "官鬼");
            result.put("午", "妻财");
            result.put("申", "父母");
        }
        if ("丑".equals(diZhi)) {
            result.put("丑", "自身");
            result.put("未", "兄弟");
            result.put("酉", "子孙");
            result.put("卯", "官鬼");
            result.put("亥", "妻财");
            result.put("巳", "父母");
        }
        if ("寅".equals(diZhi)) {
            result.put("寅", "自身");
            result.put("辰", "兄弟");
            result.put("午", "子孙");
            result.put("申", "官鬼");
            result.put("戌", "妻财");
            result.put("子", "父母");
        }
        if ("卯".equals(diZhi)) {
            result.put("卯", "自身");
            result.put("未", "兄弟");
            result.put("巳", "子孙");
            result.put("酉", "官鬼");
            result.put("丑", "妻财");
            result.put("亥", "父母");
        }
        if ("辰".equals(diZhi)) {
            result.put("辰", "自身");
            result.put("戌", "兄弟");
            result.put("申", "子孙");
            result.put("寅", "官鬼");
            result.put("子", "妻财");
            result.put("午", "父母");
        }
        if ("巳".equals(diZhi)) {
            result.put("巳", "自身");
            result.put("未", "兄弟");
            result.put("丑", "子孙");
            result.put("亥", "官鬼");
            result.put("酉", "妻财");
            result.put("卯", "父母");
        }
        if ("午".equals(diZhi)) {
            result.put("午", "自身");
            result.put("戌", "兄弟");
            result.put("辰", "子孙");
            result.put("子", "官鬼");
            result.put("申", "妻财");
            result.put("寅", "父母");
        }
        if ("未".equals(diZhi)) {
            result.put("未", "自身");
            result.put("丑", "兄弟");
            result.put("酉", "子孙");
            result.put("卯", "官鬼");
            result.put("亥", "妻财");
            result.put("巳", "父母");
        }
        if ("申".equals(diZhi)) {
            result.put("申", "自身");
            result.put("戌", "兄弟");
            result.put("子", "子孙");
            result.put("午", "官鬼");
            result.put("寅", "妻财");
            result.put("辰", "父母");
        }
        if ("酉".equals(diZhi)) {
            result.put("酉", "自身");
            result.put("丑", "兄弟");
            result.put("亥", "子孙");
            result.put("巳", "官鬼");
            result.put("卯", "妻财");
            result.put("未", "父母");
        }
        if ("戌".equals(diZhi)) {
            result.put("戌", "自身");
            result.put("辰", "兄弟");
            result.put("申", "子孙");
            result.put("寅", "官鬼");
            result.put("子", "妻财");
            result.put("午", "父母");
        }
        if ("亥".equals(diZhi)) {
            result.put("亥", "自身");
            result.put("丑", "兄弟");
            result.put("卯", "子孙");
            result.put("未", "官鬼");
            result.put("巳", "妻财");
            result.put("酉", "父母");
        }
        return result;
    }

    /**
     * 通过value获取key
     */
    public static Integer getMapKey(Map<Integer, String> map, String paramValue) {
        return map.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))
                .get(paramValue);
    }

    /**
     * 排地支
     */
    public static JSONObject paiDiZhi(int chineseTime) {
        // step1 排地支
        JSONObject diZhi = new JSONObject();
        diZhi.put("diZhi", chineseTime);
        return diZhi;
    }

    /**
     * 排六亲
     */
    public static JSONObject paiLiuQin(int chineseTime, int chineseTimeInit) {
        JSONObject liuQin = new JSONObject();

        Map<String, String> liuQinData = getLiuQin(DI_ZHI.get(chineseTimeInit));
        if (liuQinData.containsKey(DI_ZHI.get(chineseTime))) {
            liuQin.put("liuQin", liuQinData.get(DI_ZHI.get(chineseTime)));
        }
        return liuQin;
    }

    /**
     * 排六神
     */
    public static JSONObject paiLiuSheng(int chineseTime) {
        JSONObject liuSheng = new JSONObject();
        liuSheng.put("liuSheng", DI_ZHI_LIU_SHENG.get(DI_ZHI.get(chineseTime)));
        return liuSheng;
    }

    /**
     * 排五星
     */
    public static JSONObject paiWuXing(int timeGong, int day) {
        int index = timeGong - day;
        if (index < 0) {
            index += 6;
        }
        if (index > 6) {
            index -= 6;
        }
        JSONObject wuXing = new JSONObject();
        wuXing.put("wuXing", WU_XING[index % 6]);
        return wuXing;
    }

    /**
     * 排活六神
     */
    public static JSONObject paiHuoLiuSheng(int chineseTime, int timeGong) {
        int index = (chineseTime % 6 == 0 ? 6 : chineseTime % 6);
        index = timeGong - index;
        if (index < 0) {
            index += 6;
        }
        if (index > 6) {
            index -= 6;
        }
        JSONObject huoLiuSheng = new JSONObject();
        huoLiuSheng.put("huoLiuSheng", HUO_LIU_SHENG[index % 6]);
        return huoLiuSheng;
    }

    /**
     * 排活六神
     * 甲庚日顺逆起青龙；
     * 丙壬日顺逆起朱雀；
     * 戊日顺起勾陈；
     * 己日逆起腾蛇；
     * 辛乙日顺逆起白虎；
     * 癸丁日顺逆起玄武。
     */
    public static JSONObject paiHuoLiuSheng1(int dayGong, int timeGong, Map<String, String> chineseDate) {
        JSONObject huoLiuSheng = new JSONObject();
        char day = chineseDate.get("chineseDateAll").charAt(6);
        int key = 0;
        switch (day) {
            case '甲' -> key = Arrays.asList(HUO_LIU_SHENG1).indexOf("青龙");
            case '庚' -> key = Arrays.asList(HUO_LIU_SHENG1_REVERSE).indexOf("青龙");
            case '丙' -> key = Arrays.asList(HUO_LIU_SHENG1).indexOf("朱雀");
            case '壬' -> key = Arrays.asList(HUO_LIU_SHENG1_REVERSE).indexOf("朱雀");
            case '戊' -> key = Arrays.asList(HUO_LIU_SHENG1).indexOf("勾陈");
            case '己' -> key = Arrays.asList(HUO_LIU_SHENG1_REVERSE).indexOf("腾蛇");
            case '辛' -> key = Arrays.asList(HUO_LIU_SHENG1).indexOf("白虎");
            case '乙' -> key = Arrays.asList(HUO_LIU_SHENG1_REVERSE).indexOf("白虎");
            case '癸' -> key = Arrays.asList(HUO_LIU_SHENG1).indexOf("玄武");
            case '丁' -> key = Arrays.asList(HUO_LIU_SHENG1_REVERSE).indexOf("玄武");
        }
        int index = timeGong - dayGong + key;
        if (index < 0) {
            index += 6;
        }
        if (index > 6) {
            index -= 6;
        }
        switch (day) {
            case '甲', '丙', '戊', '辛', '癸' -> huoLiuSheng.put("huoLiuSheng1", HUO_LIU_SHENG1[index % 6]);
            case '庚', '壬', '己', '乙', '丁' -> huoLiuSheng.put("huoLiuSheng1", HUO_LIU_SHENG1_REVERSE[index % 6]);
        }
        return huoLiuSheng;
    }

    /**
     * 排三才
     */
    public static JSONObject paiSaiCai(int timeGong, Map<String, String> chineseDate) {
        String date = chineseDate.get("date");
        String[] split = date.split("-");
        int month = Integer.parseInt(split[1]);
        int day = Integer.parseInt(split[2]);
        Integer chineseTime = getMapKey(DI_ZHI, chineseDate.get("chineseTime"));

        month = month % 6 == 0 ? 6 : month % 6;
        day = day % 6 == 0 ? 6 : day % 6;
        chineseTime = chineseTime % 6 == 0 ? 6 : chineseTime % 6;

        JSONObject sanCai = new JSONObject();
        sanCai.put("tian", (month + timeGong - 1) % 6 == 0 ? "6" : String.valueOf((month + timeGong - 1) % 6));
        sanCai.put("ren", (day + timeGong - 1) % 6 == 0 ? "6" : String.valueOf((day + timeGong - 1) % 6));
        sanCai.put("di", (chineseTime + timeGong - 1) % 6 == 0 ? "6" : String.valueOf((chineseTime + timeGong - 1) % 6));
        return sanCai;
    }

    public static Result qiKeCommon(int month, int dayGong, int timeGong, Map<String, String> chineseDate) {
        Map<Integer, Object> result = new LinkedHashMap<>();
        int chineseTime = getMapKey(DI_ZHI, chineseDate.get("chineseTime"));
        int chineseTimeInit = getMapKey(DI_ZHI, chineseDate.get("chineseTime"));

        //先排三才
        JSONObject saiCai = paiSaiCai(timeGong, chineseDate);

        // 时宫操作
        for (int i = 0; i < 6; i++) {
            List<Object> list = new ArrayList<>();

            // step1 排地支
            JSONObject diZhi = paiDiZhi(chineseTime);

            // step2 定六亲
            JSONObject liuQin = paiLiuQin(chineseTime, chineseTimeInit);

            // step3 排六神
            JSONObject liuSheng = paiLiuSheng(chineseTime);

            // step4 起五星
            JSONObject wuXing = paiWuXing(timeGong, dayGong);

            // step5 活六神
            JSONObject huoLiuSheng = paiHuoLiuSheng(chineseTimeInit, timeGong);

            // step6
            JSONObject huoLiuSheng1 = paiHuoLiuSheng1(dayGong, timeGong, chineseDate);

            list.add(diZhi);
            list.add(liuQin);
            list.add(liuSheng);
            list.add(wuXing);
            list.add(huoLiuSheng);
            list.add(huoLiuSheng1);
            result.put(timeGong, list);

            timeGong = (timeGong % 6) + 1;
            chineseTime = (chineseTime % 12) + 2;
            if (chineseTime >= 13) {
                chineseTime = chineseTime % 12;
            }
        }

        List<Map<String, Object>> list = new ArrayList<>();

        int finalTimeGong = timeGong;
        result.forEach((key, value) -> {
            Map<String, Object> map = new LinkedHashMap<>();
            JSONArray array = JSON.parseArray(JSON.toJSONString(value));
            JSONObject diZhi = JSON.parseObject(JSON.toJSONString(array.get(0)));
            JSONObject liuQin = JSON.parseObject(JSON.toJSONString(array.get(1)));
            JSONObject liuSheng = JSON.parseObject(JSON.toJSONString(array.get(2)));
            JSONObject wuXing = JSON.parseObject(JSON.toJSONString(array.get(3)));
            JSONObject huoLiuSheng = JSON.parseObject(JSON.toJSONString(array.get(4)));
            JSONObject huoLiuSheng1 = JSON.parseObject(JSON.toJSONString(array.get(5)));

            if (month != 0) {
                map.put("month", LIU_GONG.get(month));
            }
            map.put("day", LIU_GONG.get(dayGong));
            map.put("time", LIU_GONG.get(finalTimeGong));
            map.put("gongWeiKey", String.valueOf(key));
            map.put("gongWei", LIU_GONG.get(key));
            String dizhi = DI_ZHI.get(Integer.parseInt(diZhi.get("diZhi").toString()));
            map.put("diZhi", dizhi + DI_ZHI_WU_XING.get(dizhi));
            map.put("liuQin", String.valueOf(liuQin.get("liuQin")));
            map.put("liuSheng", String.valueOf(liuSheng.get("liuSheng")));
            map.put("wuXing", String.valueOf(wuXing.get("wuXing")));
            map.put("huoLiuSheng", String.valueOf(huoLiuSheng.get("huoLiuSheng")));
            map.put("huoLiuSheng1", String.valueOf(huoLiuSheng1.get("huoLiuSheng1")));
            List<String> sanCai = new ArrayList<>();
            if (String.valueOf(key).equals(saiCai.get("tian"))) {
                sanCai.add("天");
            }
            if (String.valueOf(key).equals(saiCai.get("ren"))) {
                sanCai.add("人");
            }
            if (String.valueOf(key).equals(saiCai.get("di"))) {
                sanCai.add("地");
            }
            map.put("sanCai", sanCai);
            list.add(map);
        });

        // 三才属性
        Map<String, String> sanCaiMap = new HashMap<>();
        list.forEach(data -> {
            JSONArray sanCai = JSON.parseArray(JSON.toJSONString(data.get("sanCai")));
            if (!sanCai.isEmpty()) {
                sanCai.forEach(sanCaiData -> {
                    String diZhi = String.valueOf(data.get("diZhi"));
                    sanCaiMap.put(String.valueOf(sanCaiData), diZhi.substring(1, 2));
                });
            }
        });
        int[] shengKe = new int[]{9, 9};
        String[] ren = WU_XING_SHENG_KE.get(sanCaiMap.get("人"));
        for (int i = 0; i < ren.length; i++) {
            if (ren[i].equals(sanCaiMap.get("天"))) {
                shengKe[0] = i;
            }
            if (ren[i].equals(sanCaiMap.get("地"))) {
                shengKe[1] = i;
            }
        }
        String sanCaiStr = getShengKe("天", shengKe[0]) + " " + getShengKe("地", shengKe[1]);
        list.forEach(data -> {
            data.put("sanCai", SAN_CAI.get(sanCaiStr));
        });

        return Result.ok().put("result", JSONObject.toJSON(list).toString());
    }

    private static String getShengKe(String str, int num) {
        StringBuilder sb = new StringBuilder();
        switch (num) {
            case 0 -> sb.append("人生").append(str);
            case 1 -> sb.append("人克").append(str);
            case 2 -> sb.append(str).append("生人");
            case 3 -> sb.append(str).append("克人");
            default -> sb.append("人比").append(str);
        }
        return sb.toString();
    }

    /**
     * 一数起课
     */
    public static Result oneQiKe(int day) {
        day = day % 6 == 0 ? 6 : day % 6;
        int timeGong = 0;

        Map<String, String> chineseDate = getChineseDate();
        Integer chineseTime = getMapKey(DI_ZHI, chineseDate.get("chineseTime"));

        timeGong = (chineseTime % 6) + day - 1;
        timeGong = timeGong % 6 == 0 ? 6 : timeGong % 6;

        return qiKeCommon(0, day, timeGong, chineseDate);
    }

    /**
     * 二数起课
     */
    public static Result twoQiKe(int month, int day) {
        month = month % 6 == 0 ? 6 : month % 6;
        day = day % 6 == 0 ? 6 : day % 6;

        Map<String, String> chineseDate = getChineseDate();
        Integer chineseTime = getMapKey(DI_ZHI, chineseDate.get("chineseTime"));

        int dayGong = month + day - 1;
        dayGong = dayGong % 6 == 0 ? 6 : dayGong % 6;

        int timeGong = dayGong + chineseTime - 1;
        timeGong = timeGong % 6 == 0 ? 6 : timeGong % 6;

        return qiKeCommon(month, dayGong, timeGong, chineseDate);

    }

    /**
     * 三数起课
     */
    public static Result threeQiKe(int month, int day, int time) {
        Map<String, String> chineseDate = getChineseDate();
        month = month % 6 == 0 ? 6 : month % 6;
        day = day % 6 == 0 ? 6 : day % 6;
        time = time % 6 == 0 ? 6 : time % 6;

        int dayGong = month + day - 1;
        dayGong = dayGong % 6 == 0 ? 6 : dayGong % 6;

        int timeGong = dayGong + time - 1;
        timeGong = timeGong % 6 == 0 ? 6 : timeGong % 6;

        return qiKeCommon(month, dayGong, timeGong, chineseDate);
    }

    /**
     * 时间起课
     */
    public static Result timeQiKe(String dateStr) {
        Map<String, String> chineseDate = getChineseDate(dateStr);
        String date = chineseDate.get("date");
        String[] split = date.split("-");
        int month = Integer.parseInt(split[1]);
        int day = Integer.parseInt(split[2]);
        Integer chineseTime = getMapKey(DI_ZHI, chineseDate.get("chineseTime"));

        month = month % 6 == 0 ? 6 : month % 6;
        day = day % 6 == 0 ? 6 : day % 6;
        chineseTime = chineseTime % 6 == 0 ? 6 : chineseTime % 6;

        int dayGong = month + day - 1;
        dayGong = dayGong % 6 == 0 ? 6 : dayGong % 6;

        int timeGong = dayGong + chineseTime - 1;
        timeGong = timeGong % 6 == 0 ? 6 : timeGong % 6;

        return qiKeCommon(month, dayGong, timeGong, chineseDate);
    }

    public static void main(String[] args) {
        System.out.println(timeQiKe("2023-12-23 12:00:00"));

    }
}
